/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dataAccess;

import dataAccess.exceptions.NonexistentEntityException;
import dataAccess.exceptions.PreexistingEntityException;
import java.io.Serializable;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import entities.Device;
import entities.Lab;
import java.util.ArrayList;
import java.util.List;
import entities.TimeTable;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

/**
 *
 * @author QUY-THI
 */
public class LabJpaController implements Serializable {

    public LabJpaController(EntityManagerFactory emf) {
        this.emf = emf;
    }
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Lab lab) throws PreexistingEntityException, Exception {
        if (lab.getDeviceList() == null) {
            lab.setDeviceList(new ArrayList<Device>());
        }
        if (lab.getTimeTableList() == null) {
            lab.setTimeTableList(new ArrayList<TimeTable>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            List<Device> attachedDeviceList = new ArrayList<Device>();
            for (Device deviceListDeviceToAttach : lab.getDeviceList()) {
                deviceListDeviceToAttach = em.getReference(deviceListDeviceToAttach.getClass(), deviceListDeviceToAttach.getDeviceID());
                attachedDeviceList.add(deviceListDeviceToAttach);
            }
            lab.setDeviceList(attachedDeviceList);
            List<TimeTable> attachedTimeTableList = new ArrayList<TimeTable>();
            for (TimeTable timeTableListTimeTableToAttach : lab.getTimeTableList()) {
                timeTableListTimeTableToAttach = em.getReference(timeTableListTimeTableToAttach.getClass(), timeTableListTimeTableToAttach.getId());
                attachedTimeTableList.add(timeTableListTimeTableToAttach);
            }
            lab.setTimeTableList(attachedTimeTableList);
            em.persist(lab);
            for (Device deviceListDevice : lab.getDeviceList()) {
                Lab oldLabIDOfDeviceListDevice = deviceListDevice.getLabID();
                deviceListDevice.setLabID(lab);
                deviceListDevice = em.merge(deviceListDevice);
                if (oldLabIDOfDeviceListDevice != null) {
                    oldLabIDOfDeviceListDevice.getDeviceList().remove(deviceListDevice);
                    oldLabIDOfDeviceListDevice = em.merge(oldLabIDOfDeviceListDevice);
                }
            }
            for (TimeTable timeTableListTimeTable : lab.getTimeTableList()) {
                Lab oldLabIDOfTimeTableListTimeTable = timeTableListTimeTable.getLabID();
                timeTableListTimeTable.setLabID(lab);
                timeTableListTimeTable = em.merge(timeTableListTimeTable);
                if (oldLabIDOfTimeTableListTimeTable != null) {
                    oldLabIDOfTimeTableListTimeTable.getTimeTableList().remove(timeTableListTimeTable);
                    oldLabIDOfTimeTableListTimeTable = em.merge(oldLabIDOfTimeTableListTimeTable);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findLab(lab.getLabID()) != null) {
                throw new PreexistingEntityException("Lab " + lab + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Lab lab) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Lab persistentLab = em.find(Lab.class, lab.getLabID());
            List<Device> deviceListOld = persistentLab.getDeviceList();
            List<Device> deviceListNew = lab.getDeviceList();
            List<TimeTable> timeTableListOld = persistentLab.getTimeTableList();
            List<TimeTable> timeTableListNew = lab.getTimeTableList();
            List<Device> attachedDeviceListNew = new ArrayList<Device>();
            for (Device deviceListNewDeviceToAttach : deviceListNew) {
                deviceListNewDeviceToAttach = em.getReference(deviceListNewDeviceToAttach.getClass(), deviceListNewDeviceToAttach.getDeviceID());
                attachedDeviceListNew.add(deviceListNewDeviceToAttach);
            }
            deviceListNew = attachedDeviceListNew;
            lab.setDeviceList(deviceListNew);
            List<TimeTable> attachedTimeTableListNew = new ArrayList<TimeTable>();
            for (TimeTable timeTableListNewTimeTableToAttach : timeTableListNew) {
                timeTableListNewTimeTableToAttach = em.getReference(timeTableListNewTimeTableToAttach.getClass(), timeTableListNewTimeTableToAttach.getId());
                attachedTimeTableListNew.add(timeTableListNewTimeTableToAttach);
            }
            timeTableListNew = attachedTimeTableListNew;
            lab.setTimeTableList(timeTableListNew);
            lab = em.merge(lab);
            for (Device deviceListOldDevice : deviceListOld) {
                if (!deviceListNew.contains(deviceListOldDevice)) {
                    deviceListOldDevice.setLabID(null);
                    deviceListOldDevice = em.merge(deviceListOldDevice);
                }
            }
            for (Device deviceListNewDevice : deviceListNew) {
                if (!deviceListOld.contains(deviceListNewDevice)) {
                    Lab oldLabIDOfDeviceListNewDevice = deviceListNewDevice.getLabID();
                    deviceListNewDevice.setLabID(lab);
                    deviceListNewDevice = em.merge(deviceListNewDevice);
                    if (oldLabIDOfDeviceListNewDevice != null && !oldLabIDOfDeviceListNewDevice.equals(lab)) {
                        oldLabIDOfDeviceListNewDevice.getDeviceList().remove(deviceListNewDevice);
                        oldLabIDOfDeviceListNewDevice = em.merge(oldLabIDOfDeviceListNewDevice);
                    }
                }
            }
            for (TimeTable timeTableListOldTimeTable : timeTableListOld) {
                if (!timeTableListNew.contains(timeTableListOldTimeTable)) {
                    timeTableListOldTimeTable.setLabID(null);
                    timeTableListOldTimeTable = em.merge(timeTableListOldTimeTable);
                }
            }
            for (TimeTable timeTableListNewTimeTable : timeTableListNew) {
                if (!timeTableListOld.contains(timeTableListNewTimeTable)) {
                    Lab oldLabIDOfTimeTableListNewTimeTable = timeTableListNewTimeTable.getLabID();
                    timeTableListNewTimeTable.setLabID(lab);
                    timeTableListNewTimeTable = em.merge(timeTableListNewTimeTable);
                    if (oldLabIDOfTimeTableListNewTimeTable != null && !oldLabIDOfTimeTableListNewTimeTable.equals(lab)) {
                        oldLabIDOfTimeTableListNewTimeTable.getTimeTableList().remove(timeTableListNewTimeTable);
                        oldLabIDOfTimeTableListNewTimeTable = em.merge(oldLabIDOfTimeTableListNewTimeTable);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = lab.getLabID();
                if (findLab(id) == null) {
                    throw new NonexistentEntityException("The lab with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Integer id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Lab lab;
            try {
                lab = em.getReference(Lab.class, id);
                lab.getLabID();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The lab with id " + id + " no longer exists.", enfe);
            }
            List<Device> deviceList = lab.getDeviceList();
            for (Device deviceListDevice : deviceList) {
                deviceListDevice.setLabID(null);
                deviceListDevice = em.merge(deviceListDevice);
            }
            List<TimeTable> timeTableList = lab.getTimeTableList();
            for (TimeTable timeTableListTimeTable : timeTableList) {
                timeTableListTimeTable.setLabID(null);
                timeTableListTimeTable = em.merge(timeTableListTimeTable);
            }
            em.remove(lab);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Lab> findLabEntities() {
        return findLabEntities(true, -1, -1);
    }

    public List<Lab> findLabEntities(int maxResults, int firstResult) {
        return findLabEntities(false, maxResults, firstResult);
    }

    private List<Lab> findLabEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Lab.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Lab findLab(Integer id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Lab.class, id);
        } finally {
            em.close();
        }
    }

    public int getLabCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Lab> rt = cq.from(Lab.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }
    
}
